////////////// comment ////////////////////

#include <vector>
#include "combined.h"
#include "command.h"
#include "commandTable.h"
#include "definitions.h"
#include "log.h"
#include "stringutil.h"
#include "timestamp.h"
#include "world.h"

// Command definitions for commands beginning with the letters T through Z
// (Keep in alphabetical order... it's MUCH easier)
CmdTake::CmdTake( void ) {
	setName( "take" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "take give get drop put" );
	addSyntax( "syntax: take <object> <target>    {Ctake the given object from the target" );
}

bool CmdTake::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string target_s;
	std::string object_s;
	Character* target = NULL;
	Object* object = NULL;

	split( args, object_s, target_s );

	if ( args.empty() || object_s.empty() || target_s.empty() ) {
		character->Send( "syntax: take <object> <target>\n\r" );
		return false;
	}

	if ( ( target = World::Instance().getCharacter( target_s ) ) == NULL ) {
		character->Send( "They're not here." );
		return false;
	}

	if ( ( object = target->getObject() ) == NULL ) {
		character->Send( "They don't have that item." );
		return false;
	}

	if ( target->getLevel() > character->getLevel() - 3 ) {
		character->Send( "You can't take anything from them." );
		return false;
	}

	target->drop( object );
	character->add( object );
	character->Send( "You take " + object->getShortDesc() + " from " + target->getName() + "." );
	target->Send( character->getName() + " takes " + object->getShortDesc() + " from you." );

	return true;
}

CmdTell::CmdTell( ) {
	setName( "tell" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "tell reply" );
	addSyntax( "syntax: tell <target> <message>    {Csend the given message to target player" );
	addHelp( "\"tell\" is an OOC (Out Of Character) channel." );
}

bool CmdTell::execute( Character* character, const std::string& args ) {
	std::string name;
	std::string arg;
	std::string message;
	Character* target;

	split( args, name, arg );
	if ( ( target = World::Instance().getCharacter( name ) ) == NULL ) {
		character->Send( "That target cannot be found." );
		return false;
	}

	target->Send( character->getName() + " tells you '{Y" + arg + "{x'" );
	target->setReply( character->getName() );
	character->Send( + "You tell " + target->getName() + " '{Y" + arg + "{x'" );

	return true;
}

CmdTimers::CmdTimers( void ) {
	setName( "timers" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	setTags( "timers information server data" );
	addSyntax( "syntax: timers     {Cdisplay the timer list" );
}

bool CmdTimers::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string tmp;
	std::string when;
	int seconds = 0;
	int minutes = 0;
	int hours = 0;
	int days = 0;
	time_t current;
	time( &current );

	// Show system time...
	buf << "System Time: " << Timestamp::Instance().getDateTime() << "\n\r\n\r";

	// Show status of all scheduled timers...
	buf << "\t{!WScheduled Timers{x\n\r";
	for ( std::vector< Timer* >::iterator it = World::Instance().getTimers().begin(); it != World::Instance().getTimers().end(); it++ ) {
		// Calculate number of seconds, minutes, hours, days...
		seconds = minutes = hours = days = 0;
		when.clear();
		seconds = (int)((*it)->getWhen() - current);
		while ( seconds >= 60 ) {
			minutes++;
			seconds -= 60;
		}
		while ( minutes >= 60 ) {
			hours++;
			minutes -= 60;
		}
		while ( hours >= 24 ) {
			days++;
			hours -= 24;
		}
		if ( days > 0 )
			when << days << " days, ";
		if ( hours > 0 )
			when << hours << " hours, ";
		if ( minutes > 0 )
			when << minutes << " minutes, ";
		if ( days > 0 || hours > 0 || minutes > 0 )
			when << "and ";
		when << seconds << " seconds";
		buf << format( 15, (*it)->getName() + ":", tmp ) << when << "\n\r";
	}

	character->Send( buf );

	return true;
}

CmdTitle::CmdTitle( ) {
	setName( "title" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "title who" );
	addSyntax( "syntax: title             {Cdisplay your current title" );
	addSyntax( "        title -           {Cremove your current title" );
	addSyntax( "        title <string>    {CSet your title to the given string" );
}

bool CmdTitle::execute( Character* character, const std::string& args ) {
	std::string input = trim( args );

	if ( input.empty() ) {
		if ( character->getTitle().empty() )
			character->Send( "Your title is currently empty." );
		else
			character->Send( "Your current title: " + character->getTitle() );
		return false;
	} else if ( input == "-" ) {
		std::string empty;
		character->setTitle( empty );
		character->Send( "Title cleared." );
		return false;
	} else {
		character->setTitle( args );
		character->Send( "New title: " + character->getTitle() );
		return true;
	}
}

CmdTransport::CmdTransport( void ) {
	setName( "transport" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "goto" );
	addSyntax( "syntax: transport <player|mob> <vnum>   {Cmoves the given character or mob to the given room" );
}

bool CmdTransport::execute( Character* character, const std::string& args ) {
	std::string s_target, s_vnum;
	unsigned vnum = 0;
	Character* c_target = NULL;
	Mob* m_target = NULL;
	Room* from = character->getRoom();
	Room* to = NULL;

	split( args, s_target, s_vnum );

	if ( s_target.empty() || s_vnum.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	s_target = trim( s_target );
	vnum = atoi( s_vnum.c_str() );

	if ( ( to = World::Instance().getRoom( vnum ) ) == NULL ) {
		character->Send( "Invalid vnum." );
		return false;
	}
	if ( to == from ) {
		character->Send( getSyntax() );
		return false;
	}

	c_target = from->getCharacter( s_target );
	if ( c_target ) {
		from->drop( c_target );
		from->send( c_target->getName() + " disappears in a puff of smoke." );
		to->send( c_target->getName() + " appears in a puff of smoke." );
		to->add( c_target );
		c_target->setRoom( to );
		CmdLook look;
		look.execute( c_target, " " );
		c_target->Send( "\n\r\n\rYou've been transported." );
		return true;
	}

	m_target = from->getMob( s_target );
	if ( m_target ) {
		from->drop( m_target );
		from->send( m_target->getShortDesc() + " disappears in a puff of smoke." );
		to->send( m_target->getShortDesc() + " appears in a puff of smoke." );
		to->add( m_target );
		m_target->setRoom( to );
		return true;
	}

	character->Send( "Target not found." );
	return false;
}

CmdUp::CmdUp( void ) {
	setName( "up" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "north east south west up down movement" );
	addSyntax( "syntax: up      {cmove up" );
}

bool CmdUp::execute( Character* character, const std::string& args ) {
	Exit* in = character->getRoom()->getExit( UP );
	
	if ( !in->getThere() ) {
		character->Send( "There is no exit that way." );
		return false;
	} else if ( in->getDoor() && !in->getOpen() ) {
		character->Send( "That door is closed." );
		return false;
	} else {
		Room* from = character->getRoom();
		Room* to = NULL;
		if ( ( to = World::Instance().getRoom( in->getPoint() ) ) == NULL ) {
			character->Send( "You can't go there." );
			std::string message = "Exit inconsistency: ";
			message << from->getVnum() << " up to " << in->getPoint();
			log( message, WORLD );
			return false;
		}

		from->drop( character );
		from->send( character->getName() + " has left up." );
		to->send( character->getName() + " has arrived from below." );
		to->add( character );		character->setRoom( to );

		// Force the "look" Command...
		std::string empty;
		CmdLook commandLook;
		commandLook.execute( character, empty );
	}

	return true;
}

CmdWest::CmdWest( void ) {
	setName( "west" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "north east south west up down movement" );
	addSyntax( "syntax: west      {cmove west" );
}

bool CmdWest::execute( Character* character, const std::string& args ) {
	Exit* in = character->getRoom()->getExit( WEST );
	
	if ( !in->getThere() ) {
		character->Send( "There is no exit that way." );
		return true;
	}
	else if ( in->getDoor() && !in->getOpen() ) {
		character->Send( "That door is closed." );
		return true;
	}
	else {
		Room* from = character->getRoom();
		Room* to = NULL;
		if ( ( to = World::Instance().getRoom( in->getPoint() ) ) == NULL ) {
			character->Send( "You can't go there." );
			std::string message = "Exit inconsistency: ";
			message << from->getVnum() << " west to " << in->getPoint();
			log( message, WORLD );
			return false;
		}

		from->drop( character );
		from->send( character->getName() + " has left to the west." );
		to->send( character->getName() + " has arrived from the east." );
		to->add( character );
		character->setRoom( to );

		// Force the "look" Command...
		std::string empty;
		CmdLook commandLook;
		commandLook.execute( character, empty );
	}

	return true;
}

CmdWho::CmdWho( ) {
	setName( "who" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
}

bool CmdWho::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string level;   // Used for spaces()
	std::string useless; // Used for spaces()
	unsigned count = 0;
	
	for ( std::map<std::string,Character*>::iterator it = World::Instance().getCharacters().begin(); it != World::Instance().getCharacters().end(); ++it, ++count ) {
		buf << "\n\r ";
		if ( character->getLevel() >= BUILDER ) {
			if ( character->getLevel() >= (*it).second->getLevel() ) {
				level.clear();
				level << character->getLevel();
				buf << "[{y" << (*it).second->getLevel() << spaces( 3, level.c_str(), useless ) << "{x] ";
			} else
				buf << "      ";
		}
		buf << (*it).second->getName() << ' ' << (*it).second->getTitle() << "{x";
	}
	if ( count == 1 )
         buf.insert( 0, "\t\t1 Player" );
	else
	     buf.insert( 0, "\t\t" + to_str( count ) + " Players\n\r" );

	character->Send( buf );
	return true;
}

CmdWhos::CmdWhos( void ) {
	setName( "whos" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
}

bool CmdWhos::execute( Character* character, const std::string& args ) {
	std::string buf;
	unsigned count = 0;
	for ( std::map<std::string,Character*>::iterator it = World::Instance().getCharacters().begin(); it != World::Instance().getCharacters().end(); ++it, ++count ) {
		buf << "\n\r" << (*it).second->getName() << " " << (*it).second->getTitle() << "\n\t{C" << (*it).second->getSocket()->GetSocketIP() << "{x ({W" << (*it).second->getSocket()->GetDescriptor() << "{x)";
	}
	if ( count == 1 )
         buf.insert( 0, "\t\t1 Connection" );
	else
	     buf.insert( 0, "\t\t" + to_str( count ) + " Connections\n\r" );
	character->Send( buf );
	return true;
}
